package restless.core.audio {
	
	import com.greensock.motionPaths.RectanglePath2D;
	import flash.events.IEventDispatcher;
	import flash.media.Sound;
	import flash.media.SoundChannel;
	import neoart.flod.fred.FEPlayer;
	import restless.core.gameObjs.RLEManagedObj;
	import restless.core.gameObjs.RLEUpdateRenderObj;
	import restless.core.managers.RLESoundManager;
	import flash.events.SampleDataEvent;
	
	import flash.display.*;
	import flash.utils.*;
	import neoart.flod.*;
	import neoart.flod.core.*;
	
	/**
	 * @author Jordan Laine
	 */
	
	public class RLEMusic extends RLEManagedObj {
		
		private var vCurrentSequence:Vector.<Vector.<String>>;
		private var previousTack:String;
		private var currentTrack:String;
		
		private var float:Number;
		private var byteArray1:ByteArray;
		private var byteArray2:ByteArray;
		private var byteArray3:ByteArray;
		private var byteArray4:ByteArray;
		
		private var vByteArrays:Vector.<ByteArray>;
		
		private var vMixDownMusic:Vector.<Sound>;
		private var mixedMusic:Sound;
		private var mixedDownChannel:SoundChannel;
		
		private var vMusicClips:Vector.<RLEMusicItem>;
		private var vMusicClipIDs:Vector.<String>;
		private var vMusicTrackIDs:Vector.<String>;
		private var vMusicLineIDs:Vector.<Vector.<String>>;
		private var vMusicSequence:Vector.<Vector.<Vector.<String>>>;
		
		private var bPlayingSequencedMusic:Boolean = false;
		private var bMute:Boolean = false;
		private var nPreviousVolume:Number = 1;
		private var nVolume:Number = 1;
		
		private var vMOD:Vector.<ByteArray>;
		private var vMODIDs:Vector.<String>;
		private var flod:FEPlayer;
		private var bMOD:Boolean = false;
		
		private var tempMusicItem:RLEMusicItem;
		private var tempSound:Sound
		
		public function RLEMusic() {
			setRE();
			vMusicClips = new Vector.<RLEMusicItem>;
			vMusicClipIDs = new Vector.<String>;
		}
		
		public function addMusicClips(clips:Array, ids:Array = null):void {
			i = clips.length-1;
			for (i; i >= 0; i--) {
				if (ids != null) {
					addMusicClip(clips[i], ids[i]);
				} else {
					addMusicClip(clips[i]);
				}
			}
		}
		
		public function addMusicClip(musicClip:Sound, id:String = null):void {
			if (id == null) {
				//tempString = flash.utils.getQualifiedClassName( musicClip );
				tempString = String(musicClip);
				tempString = tempString.substring(8, tempString.length-1);
			} else {
				tempString = id;
			}
			tempMusicItem = new RLEMusicItem(this);
			tempMusicItem.setSound(musicClip);
			tempMusicItem.sID = tempString;
			vMusicClipIDs.push(tempString);
			vMusicClips.push(tempMusicItem);
		}
		
		public function addMusicSequence(trackID:String, lineID:String, vSequence:Vector.<String>):void {
			var num:int;
			tempString = trackID;
			if (vMusicSequence == null) {
				vMusicTrackIDs = new Vector.<String>;
				vMusicLineIDs = new Vector.<Vector.<String>>;
				vMusicSequence = new Vector.<Vector.<Vector.<String>>>;
				i = vMusicTrackIDs.push(tempString)-1;
			} else {
				i = vMusicTrackIDs.indexOf(tempString);
				if ( i < 0) {
					i = vMusicTrackIDs.push(tempString)-1;
				}
			}
			
			tempString = lineID;
			if (vMusicLineIDs[i].indexOf(tempString) < 0) {
				num = vMusicLineIDs[i].push(tempString)-1;
			} else {
				num = vMusicLineIDs[i].indexOf(tempString);
			}
			
			vMusicSequence[i][num].push(vSequence);
		}
		
		public function changeSequencedTrack(id:String):void {
			if (currentTrack == id) { return; }
			
			previousTack = currentTrack;
			currentTrack = id;
			i = vMusicTrackIDs.indexOf(currentTrack);
			vCurrentSequence = vMusicSequence[i];
			playSequencedMusic(false);
			playSequencedMusic(true);
		}
		
		public function playSequencedMusic(bool:Boolean):void {
			
			if (bPlayingSequencedMusic == bool) { return; }
			bPlayingSequencedMusic = bool;
			
			var tempnum:int;
			var j:int;
			
			if (bPlayingSequencedMusic) {
				if (vCurrentSequence == null) {
					vCurrentSequence = vMusicSequence[0];
				}
				
				i = vCurrentSequence.length -1;
				for (i; i >= 0; i--) {
					for (j = vCurrentSequence[i].length -1; j > -1; j--) {
						tempString = vCurrentSequence[i][j];
						tempnum = vMusicClipIDs.indexOf(tempString);
						vMusicClips[tempnum].playInLine(0, tempString);
					}
				}
			} else {
				for (i; i >= 0; i--) {
					for (j = vCurrentSequence[i].length -1; j > -1; j--) {
						tempString = vCurrentSequence[i][j];
						tempnum = vMusicClipIDs.indexOf(tempString);
						vMusicClips[tempnum].stop();
					}
				}
			}
		}
		
		public function playMusicClip(id:String):void {
			var tempNum:int = vMusicClipIDs.indexOf(id);
			vMusicClips[tempNum].play();
		}
		
		public function playNextClipInLine(lineID:String, location:int):void {
			tempString = lineID;
			
			i = vMusicTrackIDs.indexOf(currentTrack);
			vMusicLineIDs[i]
		}
		
		public function mixDown(vMusicStrings:Vector.<String>):void {
			i = vMusicStrings.length - 1;
			vByteArrays = new Vector.<ByteArray>(i);
			
			if (mixedMusic == null) {
				mixedMusic = new Sound();
				mixedDownChannel = soundM.getChannel();
				mixedDownChannel = mixedMusic.play();
				vMixDownMusic = new Vector.<Sound>(i);
			}
			
			for (i; i >= 0; i--) {
				tempString = vMusicStrings[i];
				var num:int = vMusicClipIDs.indexOf(tempString);
				vMixDownMusic[i] = vMusicClips[num].getSound(false);
			}
			
			mixedMusic.addEventListener(SampleDataEvent.SAMPLE_DATA, handleSampleData);
		}
		
		private function handleSampleData(e:SampleDataEvent):void {
			for (i = 0; i < vMixDownMusic.length-1; i++) {
				byteArray1 = new ByteArray;
				tempSound = vMixDownMusic[i];
				tempSound.extract(byteArray1, 8 << 10, e.position);
				byteArray1.position = 0;
				vByteArrays.push(byteArray1);
			}
			
			if (i == 1) {
				byteArray1 = vByteArrays[0];
				byteArray2 = vByteArrays[1];
				while (byteArray1.bytesAvailable > 0 && byteArray2.bytesAvailable > 0) {
					float = ( byteArray1.readFloat() + byteArray2.readFloat() ) * .5;
					e.data.writeFloat( float );
					e.data.writeFloat( float );
				}
				
				if (byteArray1.bytesAvailable > 0) {
					e.data.writeBytes(byteArray1, byteArray1.position, byteArray1.bytesAvailable);
				} else if(byteArray2.bytesAvailable > 0) {
					e.data.writeBytes(byteArray2, byteArray2.position, byteArray2.bytesAvailable);
				}
			} else if (i == 2) {
				byteArray1 = vByteArrays[0];
				byteArray2 = vByteArrays[1];
				byteArray3 = vByteArrays[2];
				while (byteArray1.bytesAvailable > 0 && byteArray2.bytesAvailable > 0 && byteArray3.bytesAvailable > 0) {
					float = ( byteArray1.readFloat() + byteArray2.readFloat() + byteArray3.readFloat() ) / 3;
					e.data.writeFloat( float );
					e.data.writeFloat( float );
				}
				
				if (byteArray1.bytesAvailable > 0) {
					e.data.writeBytes(byteArray1, byteArray1.position, byteArray1.bytesAvailable);
				} else if(byteArray2.bytesAvailable > 0) {
					e.data.writeBytes(byteArray2, byteArray2.position, byteArray2.bytesAvailable);
				} else if(byteArray3.bytesAvailable > 0) {
					e.data.writeBytes(byteArray3, byteArray3.position, byteArray3.bytesAvailable);
				}
			} else if (i == 3) {
				byteArray1 = vByteArrays[0];
				byteArray2 = vByteArrays[1];
				byteArray3 = vByteArrays[2];
				byteArray4 = vByteArrays[3];
				while (byteArray1.bytesAvailable > 0 && byteArray2.bytesAvailable > 0 && byteArray3.bytesAvailable > 0 && byteArray4.bytesAvailable > 0) {
					float = ( byteArray1.readFloat() + byteArray2.readFloat() + byteArray3.readFloat() + byteArray4.readFloat()) * .25;
					e.data.writeFloat( float );
					e.data.writeFloat( float );
				}
				
				if (byteArray1.bytesAvailable > 0) {
					e.data.writeBytes(byteArray1, byteArray1.position, byteArray1.bytesAvailable);
				} else if(byteArray2.bytesAvailable > 0) {
					e.data.writeBytes(byteArray2, byteArray2.position, byteArray2.bytesAvailable);
				} else if(byteArray3.bytesAvailable > 0) {
					e.data.writeBytes(byteArray3, byteArray3.position, byteArray3.bytesAvailable);
				} else if(byteArray4.bytesAvailable > 0) {
					e.data.writeBytes(byteArray4, byteArray4.position, byteArray4.bytesAvailable);
				}
			} else if (i == 0) {
				byteArray1 = vByteArrays[0];
				while (byteArray1.bytesAvailable > 0) {
					float = byteArray1.readFloat();
					e.data.writeFloat( float );
					e.data.writeFloat( float );
				}
				
				if (byteArray1.bytesAvailable > 0) {
					e.data.writeBytes(byteArray1, byteArray1.position, byteArray1.bytesAvailable);
				}
			}	
		}
		
		public function set mute(bool:Boolean):void {
			if (bool == bMute) { return; }
			bMute = bool;
			
			if (bMute) {
				nPreviousVolume = volume;
				volume = 0;
			} else {
				volume = nPreviousVolume;
			}
		}
		
		public function get mute():Boolean {
			return bMute;
		}
		
		public function set volume(num:Number):void {
			if (bMute) { return; }
			
			nPreviousVolume = nVolume;
			if (num > 1) { nVolume = 1; }
			else if (num < 0) { nVolume = 0; }
			else { nVolume = num; }
			
			if (bMOD) { flod.volume = nVolume; }
			else {
				i = vMusicClips.length - 1;
				for (i; i > -1; i--) {
					tempMusicItem = vMusicClips[i];
					tempMusicItem.volume = nVolume;
				}
			}
		}
		
		public function get volume():Number {
			return nVolume;
		}
		
		public function set MOD(bool:Boolean):void {
			if (bMOD == bool) { return; }
			bMOD = bool;
			
			if (bMOD) {
				if (!flod) {
					flod = new FEPlayer;
					flod.volume = nVolume;
				}
				if (!vMOD) {
					vMOD = new Vector.<ByteArray>;
				}
			} else {
				flod.stop();
				flod = null;
				vMOD = null;
			}
		}
		
		public function addMODTrack(music:ByteArray, id:String):void {
			vMOD.push(music);
			vMODIDs.push(id);
		}
		
		public function stopMOD():void {
			flod.stop();
		}
		
		public function pauseMOD():void {
			flod.pause();
		}
		
		public function playMOD(id:String):void {
			var num:int = vMODIDs.indexOf(id);
			flod.load(vMOD[num]);
			flod.play();
		}
		
		public function unloadMODs():void {
			if (vMOD) {
				if (flod) {
					flod.stop();
				}
				vMOD.length = 0;
				vMODIDs.length = 0;
			}
		}
	}
}